use anyhow::Result;
use std::fs::{self, DirEntry, OpenOptions};
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};

const FOLDER_NAME: &str = "kb"; // 知识库存储的名称

struct KbFolder {
    path: PathBuf,
}

impl KbFolder {
    pub fn new() -> Self {
        Self {
            path: PathBuf::from(FOLDER_NAME),
        }
    }

    pub fn exists(&self) -> bool {
        self.path.exists()
    }
    pub fn init(&self) -> Result<()> {
        if !self.exists() {
            fs::create_dir(&self.path)?;
        }
        Ok(())
    }
    pub fn path(&self) -> &Path {
        &self.path
    }
}

fn get_kb_file_name(kb_name: &Option<&String>) -> Option<PathBuf> {
    return kb_name.map(|name| Path::new(FOLDER_NAME).join(name));
}

pub fn append_to_kb(kb_name: &Option<&String>, question: &str, answer: &str) -> Result<()> {
    if let Some(kb_file_path) = get_kb_file_name(kb_name) {
        // 初始化目录
        KbFolder::new().init()?;

        // 打开文件，如果不存在则创建
        let mut file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(&kb_file_path)?;

        // 检查文件是否需要添加分隔符
        if file.metadata()?.len() > 0 {
            file.write_all(b"\n==message-seperator==\n")?;
        }

        // 写入消息
        file.write_all(format!("{}\n===answer===\n{}", question, answer).as_bytes())?;

        Ok(())
    } else {
        Ok(())
    }
}

fn is_regular_file(entry: &DirEntry) -> bool {
    entry.metadata().map(|m| m.is_file()).unwrap_or(false)
}

fn is_hidden_file(entry: &DirEntry) -> bool {
    entry.file_name().to_string_lossy().starts_with('.')
}

fn sort_entries(mut entries: Vec<DirEntry>) -> Vec<DirEntry> {
    entries.retain(|e| is_regular_file(e) && !is_hidden_file(e));

    entries.sort_by(|a, b| {
        let a_meta = a.metadata().unwrap();
        let b_meta = b.metadata().unwrap();

        // 首先按修改时间排序，最近的在前
        let time_cmp = b_meta.modified().into_iter().cmp(a_meta.modified());
        if time_cmp != std::cmp::Ordering::Equal {
            time_cmp
        } else {
            // 如果修改时间相同，则按文件名排序
            a.file_name().cmp(&b.file_name())
        }
    });

    entries
}
fn load_sorted_kb_entries() -> Result<Vec<DirEntry>> {
    let kb_folder = KbFolder::new();
    if !kb_folder.exists() {
        println!("Directory {} does not exist.", kb_folder.path().display());
        return Ok(Vec::new());
    }

    let entries = fs::read_dir(kb_folder.path())?
        .map(|res| res.map(|e| e))
        .collect::<Result<Vec<_>, io::Error>>()?;

    let sorted_entries = sort_entries(entries);
    Ok(sorted_entries)
}

pub fn list_kb_number() -> Result<()> {
    let sorted_entries = load_sorted_kb_entries()?;

    for (index, entry) in sorted_entries.iter().enumerate() {
        println!("{}: {}", index, entry.file_name().to_string_lossy());
    }

    Ok(())
}

fn load_kb_message(file_name: &str) -> Result<String> {
    let path = PathBuf::from(FOLDER_NAME).join(file_name);
    Ok(fs::read_to_string(path)?)
}

pub fn get_kb_message(kb_number: &Option<usize>) -> Option<String> {
    if kb_number.is_none() {
        return None;
    }
    if let Ok(sorted_entries) = load_sorted_kb_entries() {
        return sorted_entries
            .get(kb_number.unwrap())
            .map(|entry| entry.file_name().to_string_lossy().into_owned())
            .map(|file_name| load_kb_message(&file_name).ok())?;
    }
    None
}

pub fn is_kb_duplicated(kb_name: &Option<&String>) -> bool {
    get_kb_file_name(kb_name)
        .map(|file_name| file_name.exists())
        .unwrap_or(false)
}
